

package tomkitty;

import java.net.*;
import java.io.*;
import java.util.*;

public class TkHttpHandler extends Turdlet {

  public void doit() {

    try {
      if (request == null) {
        throw new TkResponseException(HTTP_SERVER_ERROR);
      }

      BufferedReader br = new BufferedReader(new InputStreamReader(
            request.getSocket().getInputStream()));
      String firstLine;

      // read in the request header request-line
      if ( (firstLine = br.readLine()) == null) {
        throw new TkResponseException(HTTP_BAD_REQUEST);
      }

      Debug.d("Request:  " + firstLine);

      // parse the request header fields
      String line;
      while( (line = br.readLine()) != null ) {
        if (line.length() == 0) {
          break;
        } else {
          String[] f = line.split(":", 2);
          request.setField(f[0].trim(), f[1].trim());
          //Debug.d(f[0] + ":" + f[1]);
        }
      }

      // fail if no hostname provided (RFC2616 section 14.23)
      String host;
      if ( (host = request.getField("Host")) == null ) {
        throw new TkResponseException(HTTP_BAD_REQUEST);
      }

      //
      // expect, according to RFC-2616 (section 5), something of the form
      //
      //     RequestLine = Method SP Request-URI SP HTTP-Version CRLF
      //
      // where
      //
      //     Method = "OPTIONS" | "GET" | "HEAD" | "POST" | "PUT" | "DELETE" |
      //              "TRACE" | "CONNECT"
      //
      //     Request-URI = "*" | absoluteURI | abs_path | authority
      //
      //    HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
      //    

      // tokenized request-line
      String[] reqLine = firstLine.split(" ", 3);

      String method;      // HTTP method
      String uriStr;      // HTTP request URI
      String version;     // HTTP version

      // check for correct number of tokens
      if (reqLine.length < 3) {
        throw new TkResponseException(HTTP_BAD_REQUEST);
      }

      // get the request method
      method = reqLine[0];
      
      // supported methods are GET, HEAD, and POST
      if ( ! method.equals("GET") && 
           ! method.equals("HEAD") &&
           ! method.equals("POST")) {
        throw new TkResponseException(HTTP_INTERNAL_ERROR);
      }

      // indicate whether or not to send anything after the headers
      response.headersOnly(method.equals("HEAD"));

      // add the host part to the URI, and http as the scheme, of course
      uriStr = "http://" + host + reqLine[1];
      
      // get http-version: must be HTTP/?.? where ? is a digit
      String[] verParts = reqLine[2].split("/");
      if (verParts.length != 2 || ! verParts[0].equals("HTTP")) {
        throw new TkResponseException(HTTP_BAD_REQUEST);
      }

      version = verParts[1];

      // version must be DIGIT dot DIGIT
      if ( version.length() < 3 ||
           (version.charAt(0) < 48 || version.charAt(0) > 57) ||
           (version.charAt(1) != '.') ||
           (version.charAt(2) < 48 || version.charAt(2) > 57) ) {
        throw new TkResponseException(HTTP_BAD_REQUEST);
      }

      request.setMethod(method);
      request.setVersionMajor(new Integer(version.charAt(0)).intValue());
      request.setVersionMinor(new Integer(version.charAt(2)).intValue());
      
      // parse the request URI
      try {
        request.setUri(new URI(uriStr));
        request.setOrigUri(new URI(uriStr));
      } catch (URISyntaxException uri_e) {
        throw new TkResponseException(HTTP_BAD_REQUEST);
      }

    } catch (TkResponseException tk_e) {
      response.setStatus(tk_e.getMessage());
    } catch (Exception ex_e) {
      ex_e.printStackTrace();
      response.setStatus(HTTP_SERVER_ERROR);
    }

  }

}



